﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Diagnostics;
using System.Xml.Serialization;

namespace MuYue.Plugin
{
    /// <summary>
    /// 插件管理器
    /// </summary>
    public class PluginManager
    {
        #region 单例模式创建
        public static PluginManager Create() {
            if (manager == null) {
                lock (locker) {
                    if (manager == null) {
                        manager = new PluginManager();
                    }
                }
            }
            return manager;
        }
        private static object locker = new object();
        private static PluginManager manager;
        #endregion

        /// <summary>
        /// 插件静态初始化
        /// </summary>
        private PluginManager() {
            pluginContainers = new List<PluginContainer>();
        }

        /// <summary>
        /// 插件目录
        /// </summary>
        private string addinsPath = "./addins/";

        /// <summary>
        /// 插件列表
        /// </summary>
        private readonly List<PluginContainer> pluginContainers;

        /// <summary>
        /// 将目录添加到插件目录扫描容器里
        /// </summary>
        /// <param name="directory">插件目录</param>
        /// <param name="relative">是否是相对路径</param>
        public void SetAddinsPath(string directory, bool relative = true) {
            if (string.IsNullOrWhiteSpace(directory))
            {
                throw new Exception("请提供插件的目录");
            }
            if (relative)
                directory = Path.Combine(Directory.GetCurrentDirectory(), directory);
            this.addinsPath = directory;
        }



        /// <summary>
        /// 扫描插件
        /// 1.再插件容器中扫描信息
        /// </summary>
        public void StartService() {
            lock (pluginContainers)
            {
                var files = Directory.GetFiles(addinsPath, "*.addon", SearchOption.AllDirectories);
                var ser = new XmlSerializer(typeof(PluginAttribute));
                foreach (var file in files)
                {
                    using (var fs = File.OpenRead(file))
                    {
                        var attribute = (PluginAttribute)ser.Deserialize(fs);
                        bool more = false;
                        foreach (var temp in pluginContainers)
                        {
                            if (temp.PluginXml.Identify == attribute.Identify)
                            {
                                more = true;
                                break;
                            }
                        }
                        if (!more)
                        {
                            var container = new PluginContainer(attribute, Path.GetDirectoryName(file));
                            pluginContainers.Add(container);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 使用接口来获取插件实例
        /// </summary>
        /// <typeparam name="T">接口类型</typeparam>
        /// <returns>返回插件实例</returns>
        public T GetPlugin<T>(params object[] args) {

            var interfaceType = typeof(T);
            var iList = new List<PluginContainer>();
            
            foreach (var container in pluginContainers) {
                if (interfaceType.FullName == container.PluginXml.PluginInterfaceName)
                    iList.Add(container);
            }

            if (iList.Count == 1)
                return (T)iList[0].CreateInstance(args);

            if (iList.Count == 0)
                iList = pluginContainers;

            foreach (var container in iList) {
                if (interfaceType == container.PluginInterfaceType)
                    return (T)container.CreateInstance(args);
            }
            throw new Exception("插件容器里面没有该插件");
        }

        /// <summary>
        /// 通过插件的ID来识别插件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="guid">插件ID</param>
        /// <param name="args">插件初始化参数</param>
        /// <returns></returns>
        public T GetPluginByGUID<T>(string guid, params object[] args) {
            foreach (var container in pluginContainers) {
                if (container.PluginXml.Id == guid)
                    return (T)container.CreateInstance(args);
            }
            throw new Exception("插件容器里面没有该id的插件");
        }

        /// <summary>
        /// 通过插件实现类名来创建插件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="identify">插件类名</param>
        /// <param name="args">插件初始化参数</param>
        /// <returns></returns>
        public T GetPluginByIdentify<T>(string identify, params object[] args) {
            foreach (var container in pluginContainers) {
                if (container.PluginXml.Identify == identify)
                    return (T)container.CreateInstance(args);
            }
            throw new Exception("插件容器里面没有该id的插件");
        }

        /// <summary>
        /// 获取插件容器
        /// </summary>
        /// <param name="identify">类名</param>
        /// <returns></returns>
        public PluginContainer GetContainerByClassName(string identify) {
            foreach (var container in pluginContainers) {
                if (container.PluginXml.Identify == identify)
                    return container;
            }
            throw new Exception("插件容器里面没有该id的插件");
        }
    }
}
